package com.xxgc.cloud.auth.springcloudauth.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import com.xxgc.cloud.api.result.Result;
import com.xxgc.cloud.auth.springcloudauth.controller.dto.UserLoginDTO;
import com.xxgc.cloud.auth.springcloudauth.controller.dto.UsersRegisterDTO;
import com.xxgc.cloud.auth.springcloudauth.controller.pojo.UserRolesAndPermissions;
import com.xxgc.cloud.auth.springcloudauth.controller.vo.UsersLoginVO;
import com.xxgc.cloud.auth.springcloudauth.entity.Users;
import com.xxgc.cloud.auth.springcloudauth.service.IUsersService;
import com.xxgc.cloud.common.redis.RedisUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.Pattern;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @program: SpringCloudStudy
 * @description: 用户登录
 * @author: shijiayi
 * @create: 2022-11-22 14:36
 **/
@Api(tags = "用户注册登录")
@RestController
@Validated
@Slf4j
@RefreshScope
@RequestMapping("/login")
public class UserLoginRegisterController {

    //jwt的key
    @Value("${jwt.key}")
    private String jwtKey;

    @Value("${jwt.expiration-time}")
    private Integer expirationTime;//过期时间1分钟

    @Value("${redis.login.key}")
    private String redisLoginKey;

    @Resource
    private IUsersService ius;

    @Autowired
    private RedisUtil redisUtil;

    @ApiOperation(value = "最高信用分登录（普通登录）")
    @PostMapping("/simpleLogin")
    public Result userSimpleLogin(String userName, String passWord) {
        return Result.success("登录成功");
    }

    /**
     * entity
     * 表数据模型
     * vo
     * 返回给前端返回的数据模型
     * dto
     * 接收前端的数据数据模型
     * 通常为前端传入的参数类
     */
    //@StackTraceElementSize(stackTraceElementSize = 5)
    @ApiOperation(value = "用户注册")
    @PostMapping("/userRegister")
    public Result userRegister(@Valid @RequestBody UsersRegisterDTO usersRegisterDTO) {
        //DTO转Entity
        Users users = new Users();
        BeanUtil.copyProperties(usersRegisterDTO, users);
        ius.userRegister(users);
        //两种做法
        //1、用户注册过后直接到首页 那就必须返回VO
        //2、用户注册过后跳转到登录页，再登录，就无需VO
        return Result.success();
    }


    @ApiOperation(value = "获取手机验证码")
    @GetMapping("/getPhoneVerCode")
    public Result getPhoneVerCode(
            @Pattern(regexp = "^((13[0-9])|(14(0|[5-7]|9))|(15([0-3]|[5-9]))|(16(2|[5-7]))|(17[0-8])|(18[0-9])|(19([0-3]|[5-9])))\\d{8}$", message = "手机号格式不正确")
            @RequestParam String phoneNum,
            HttpServletRequest request,
            HttpServletResponse response) {
        //1、生成一个验证码
        String randomStr = RandomUtil.randomString(6);
        //2、生成一个UUID
        //String uuId = IdUtil.simpleUUID();
        //2.5 把UA信息存入到数据库
        /*String uaStr = request.getHeader("User-Agent");
        UserAgent ua = UserAgentUtil.parse(uaStr);*/
        //2.6 把信息存入到redis 登录时进行判断
        /*ua.getBrowser().toString();//Chrome
        ua.getVersion();//14.0.835.163
        ua.getOs().toString();//Windows 7*/
        //3、通过UUID（手机号）把验证码存入到Redis设置过期时间3分钟
        //key手机号 value验证码
        //response.setHeader("randomKey",uuId);

        //3、调用SMS服务发送短信给用户

        //4、如果成功 把数据数据以 key=手机号 value=验证码 存入到redis并且3分钟过期

        //5、完成请求返回
        return Result.success(randomStr);
    }

    //用户登录
    @ApiOperation(value = "用户登录")
    @PostMapping("/userLogin")
    public Result<UsersLoginVO> userLogin(@Valid @RequestBody UserLoginDTO userLoginDTO) {
        //1、通过查询得到盐值
        Users u1 = ius.selectSaltByPhoneNumber(userLoginDTO.getPhoneNumber());
        if(u1 == null){
            return Result.error("用户名或密码错误");
        }

        //2、对密码进行md5加密
        Digester md5 = new Digester(DigestAlgorithm.MD5);
        md5.setSalt(u1.getSalt().getBytes());
        String digestHex = md5.digestHex(userLoginDTO.getUserPass());
        userLoginDTO.setUserPass(digestHex);

        //3、DTO转Entity查询用户
        Users users = new Users();
        BeanUtil.copyProperties(userLoginDTO, users);
        Users userEntity = ius.userLogin(users);
        if(userEntity == null){
            return Result.error("用户名或密码错误");
        }
        Long uId = userEntity.getId();
        DateTime now = DateTime.now();
        DateTime newTime = now.offsetNew(DateField.MINUTE, expirationTime);
        //4、用户信息包装成Token
        Map<String, Object> map = new HashMap<String, Object>() {
            private static final long serialVersionUID = 1L;
            {
                put("uid", uId);//用户id
                //签发时间
                put(JWTPayload.ISSUED_AT, now);
                //过期时间
                put(JWTPayload.EXPIRES_AT, newTime);
                //生效时间
                put(JWTPayload.NOT_BEFORE, now);
            }
        };
        //签发token
        String token = JWTUtil.createToken(map, jwtKey.getBytes());

        //5、把Entity和Vo进行转换
        UsersLoginVO usersLoginVO = new UsersLoginVO();
        BeanUtil.copyProperties(userEntity, usersLoginVO);
        usersLoginVO.setToken(token);

        //6、Redis保存用户 角色和权限信息
        String redisKey = redisLoginKey+uId;

        //添加用户的权限信息和角色信息一同放入Redis
        UserRolesAndPermissions urap = ius.selectRoAndPeByUserId(uId);

        //把token缓存到数据库中
        redisUtil.setStr(redisKey,token);
        //过期时间 已秒为单位，所以要设置过期时间
        redisUtil.expire(redisKey,expirationTime, TimeUnit.SECONDS);
        //把角色信息和权限信息放到redis
        if(urap.getRoles() != null){
            String setRolesRedisKey = redisKey+"_roles";
            redisUtil.addSetByList(setRolesRedisKey, Arrays.asList(urap.getRoles().toArray()));
            redisUtil.expire(setRolesRedisKey,expirationTime, TimeUnit.SECONDS);
        }
        if(urap.getPermissions() != null){
            //把权限信息放到redis
            String setPermissionsRedisKey = redisKey+"_permissions";
            redisUtil.addSetByList(setPermissionsRedisKey, Arrays.asList(urap.getPermissions().toArray()));
            redisUtil.expire(setPermissionsRedisKey,expirationTime, TimeUnit.SECONDS);
        }

        //8、更新最后一次登录时间
        userEntity.setLastTime(LocalDateTime.now());
        ius.updateLastLoginTime(userEntity);
        return Result.success(usersLoginVO);
    }


}
